// Add client files

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")

// Include shared file

include('shared.lua')

// When entity is initialized

function ENT:Initialize()
	// Set the model
	
	self.Entity:SetModel("models/dav0r/hoverball.mdl")
	
	// Don't use the model's Physics object, create a perfect sphere
	
	self.Entity:PhysicsInitSphere(8, "metal_bouncy")
	
	// Wake up our Physics object so we don't start asleep
	
	local Phys = self.Entity:GetPhysicsObject()
	
	if (Phys:IsValid()) then 
		Phys:SetMass(100)
		Phys:EnableGravity(false)
		Phys:Wake() 
	end
	
	// Values
	
	self.Entity.Activated = true
	
	// Networked
	
	self.Entity:SetNetworkedBool("Hoverball.Activated", true)
	
	// Start the motion controller
	
	self.Entity:StartMotionController()
	
	// Variables
	
	self.Fraction  = 0
	self.ZVelocity = 0	
	
	// Call some functions
	
	self:SetTargetZ(self.Entity:GetPos().z)
	self:SetSpeed(1)
	
	// Wire
	
	if (Wire_CreateOutputs) then
		self.Outputs = Wire_CreateOutputs(self.Entity, {"Active"})
	end
	
	if (Wire_TriggerOutput) then
		Wire_TriggerOutput(self.Entity, "Active", 1)
	end
end

function ENT:OnRestore()
	self.ZVelocity = 0
end

// Think function called every frame

function ENT:Think()
	self.Entity:NextThink(CurTime() + 0.25)

	self.Entity:SetNetworkedInt("TargetZ", self:GetTargetZ())
	
	return true
end

// Physics simulate

function ENT:PhysicsSimulate(Phys, DeltaTime)
	if not (self.Entity.Activated) then return end
	
	if (self.ZVelocity != 0) then
		self:SetTargetZ(self:GetTargetZ() + (self.ZVelocity * DeltaTime * self:GetSpeed()))
		
		self.Entity:GetPhysicsObject():Wake()
	end
	
	Phys:Wake()
	
	local Pos           = Phys:GetPos()
	local Vel           = Phys:GetVelocity()
	local Dist          = self:GetTargetZ() - Pos.z
	local AirResistance = self:GetAirResistance()
	
	if (Dist == 0) then return end
	
	local Exponent = Dist ^ 2
	
	if (Dist < 0) then
		Exponent = Exponent * -1
	end
	
	Exponent = Exponent * DeltaTime * 300
	
	local VelocityPhysics = Phys:GetVelocity()
	local Vel = VelocityPhysics.z
	
	Exponent = Exponent - (Vel * DeltaTime * 600 * (AirResistance + 1))
	
	Exponent = math.Clamp(Exponent, -5000, 5000)
	
	local Linear = Vector(0,0,0)
	local Angular = Vector(0,0,0)
	
	Linear.z = Exponent
	
	if (AirResistance > 0) then
		Linear.y = VelocityPhysics.y * -1 * AirResistance
		Linear.x = VelocityPhysics.x * -1 * AirResistance
	end

	return Angular, Linear, SIM_GLOBAL_ACCELERATION
end

// Set Z velocity

function ENT:SetZVelocity(Z)
	if (Z != 0) then
		self.Entity:GetPhysicsObject():Wake()
	end

	self.ZVelocity = Z * FrameTime() * 5000
end

// Get the air resistance

function ENT:GetAirResistance()
	return self.Entity:GetVar("AirResistance", 0)
end

// Set the friction in the air

function ENT:SetAirResistance(Num)
	self.Entity:SetVar("AirResistance", Num)
	
	self:UpdateLabel()
end

// Set hoverball strength

function ENT:SetStrength(Strength)

	local Phys = self.Entity:GetPhysicsObject()
	
	if (Phys:IsValid()) then 
		Phys:SetMass(150 * Strength)
	end

	self:UpdateLabel()
end

// Numpad control

function ENT.Activate(Player, Entity, Key, IDX)
	if (!Entity:IsValid()) then return false end
	
	if (Key) then
		Entity:SetZVelocity(1)
	else
		Entity:SetZVelocity(0)
	end
	
	return true
end

// Toggle

function ENT.Toggle(Player, Entity, Key, IDX)
	if (!Entity:IsValid()) then return false end
	
	if not (Key) then
		Entity:SetTargetZ(Entity:GetPos().z)
		
		Entity.Activated = not Entity.Activated
		
		Entity:SetNetworkedBool("Hoverball.Activated", Entity.Activated)
		
		Entity:GetPhysicsObject():EnableCollisions(Entity.Activated)
		
		if (Entity.Stop == 1) then
			Entity:GetPhysicsObject():SetVelocity(Vector(0, 0, 0))
		end
		
		local Gravity = not Entity.Activated
		
		Entity:GetPhysicsObject():EnableGravity(Gravity)
		
		if (Entity.Activated) then
			Entity:SetStrength(Entity.Strength)
		else
			Entity:GetPhysicsObject():SetMass(10)
		end
		
		local Number = 0
		
		if (Entity.Activated) then
			Number = 1
		end
		
		if (Wire_TriggerOutput) then
			Wire_TriggerOutput(Entity, "Active", Number)
		end
	end
	
	return true
end

// Deactivate

function ENT.Deactivate(Player, Entity, Key, IDX)
	if (!Entity:IsValid()) then return false end
	
	if (Key) then
		Entity:SetZVelocity(-1)
	else
		Entity:SetZVelocity(0)
	end
	
	return true
end

// Register numpad functions

numpad.Register("Hoverball.Activate", ENT.Activate)
numpad.Register("Hoverball.Deactivate", ENT.Deactivate)
numpad.Register("Hoverball.Toggle", ENT.Toggle)